/**
 * Copyright 2016-2018 mobaas.com
 */
package com.mobaas.devops.node;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;

/**
 * 
 * @author billy zhang
 *
 */
public class HttpUtil {

	private static final String TAG = "mobaas";  
	private static final int MAX_TIMEOUT = 150000;  // 150秒
	
	private static PoolingHttpClientConnectionManager connMgr;
	private static RequestConfig requestConfig;
	
	private HttpUtil() {
	}

	 static {
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());

        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        // 在提交请求之前 测试连接是否可用
        configBuilder.setStaleConnectionCheckEnabled(true);
        requestConfig = configBuilder.build();
    }
	 
	 private static RequestConfig buildRequestConfig(int timeout) {
		 return RequestConfig.custom()
				 .setConnectTimeout(timeout * 1000)
				.setSocketTimeout(timeout * 1000)
				.setConnectionRequestTimeout(timeout * 1000)
				.setStaleConnectionCheckEnabled(true)
				.build();
	 }

	public static HttpResult get(String urlString) {
		// 创建默认的HttpClient实例.
        CloseableHttpClient httpclient = HttpClients.custom()
        		.setDefaultRequestConfig(requestConfig)
        		.build();
        
        HttpResult result = new HttpResult();
        try {
        	CloseableHttpResponse resp = httpclient.execute(new HttpGet(urlString));
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		    
		return result;
	}
	
	public static HttpResult get(String urlString, int timeout) {
		
		// 创建默认的HttpClient实例.
        CloseableHttpClient httpclient = HttpClients.custom()
        		.setDefaultRequestConfig(buildRequestConfig(timeout))
        		.build();
        
        HttpResult result = new HttpResult();
        try {
        	CloseableHttpResponse resp = httpclient.execute(new HttpGet(urlString));
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		    
		return result;
	}
	
	public static HttpResult getSSL(String urlString, SSLContext sslContext) {
		// 创建默认的HttpClient实例.
        CloseableHttpClient httpclient = HttpClients.custom()
        		.setDefaultRequestConfig(requestConfig)
        		.setSSLContext(sslContext)
        		.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
        		.build();
        HttpResult result = new HttpResult();
        try {
        	CloseableHttpResponse resp = httpclient.execute(new HttpGet(urlString));
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		    
		return result;
	}
	
	public static HttpResult post(String urlString, Map<String, String> params) {
		
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 

    		ArrayList<NameValuePair> nvps = new ArrayList<>();
    		
    		for (String key : params.keySet()) {
    			nvps.add(new BasicNameValuePair(key, params.get(key)));
    		}
    		//转码  封装成请求实体
    		httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
	    	
        	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}
	
	public static HttpResult post(String urlString, Map<String, String> params, int timeout) {
		
		RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(timeout);
        // 设置读取超时
        configBuilder.setSocketTimeout(timeout);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(timeout);
        // 在提交请求之前 测试连接是否可用
        configBuilder.setStaleConnectionCheckEnabled(true);
        
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig( configBuilder.build() )
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 

    		ArrayList<NameValuePair> nvps = new ArrayList<>();
    		
    		for (String key : params.keySet()) {
    			nvps.add(new BasicNameValuePair(key, params.get(key)));
    		}
    		//转码  封装成请求实体
    		httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
	    	
        	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}

	public static HttpResult post(String urlString, String postData) {
		
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 
    		httpPost.setHeader("Content-Type", "application/json");
	    	if (!StringUtils.isEmpty(postData)) {
	    		httpPost.setEntity(new StringEntity(postData, "utf-8"));
	    	}
	    	
        	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}
	
    public static HttpResult postSSL(String urlString, String postData, SSLContext sslContext) {
		
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.setSSLContext(sslContext)
        		.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 
    		httpPost.setHeader("Content-Type", "application/json");
	    	if (!StringUtils.isEmpty(postData)) {
	    		httpPost.setEntity(new StringEntity(postData, "utf-8"));
	    	}
	    	
	    	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}

    public static HttpResult postSSL(String urlString, String postData, Map<String, String> headers, SSLContext sslContext) {
		
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.setSSLContext(sslContext)
        		.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 
    		httpPost.setHeader("Content-Type", "application/json");
    		for (String key : headers.keySet()) {
    			httpPost.setHeader(key, headers.get(key));
    		}
    		
	    	if (!StringUtils.isEmpty(postData)) {
	    		httpPost.setEntity(new StringEntity(postData, "utf-8"));
	    	}
	    	
	    	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();

	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}

	public static HttpResult postSSL(String urlString, byte[] postData, String contentType, SSLContext sslContext) {
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.setSSLContext(sslContext)
        		.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 
    		httpPost.setHeader("Content-Type", contentType);
	    	if (postData != null) {
	    		httpPost.setEntity(new ByteArrayEntity(postData));
	    	}
	    	
	    	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
        	
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}
	
	public static HttpResult postSSL(String urlString, byte[] postData, String contentType, Map<String, String> headers, SSLContext sslContext) {
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.setSSLContext(sslContext)
        		.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {
    		HttpPost httpPost = new HttpPost(urlString); 
    		httpPost.setHeader("Content-Type", contentType);
    		for (String key : headers.keySet()) {
    			httpPost.setHeader(key, headers.get(key));
    		}
    		
	    	if (postData != null) {
	    		httpPost.setEntity(new ByteArrayEntity(postData));
	    	}
	    	
	    	CloseableHttpResponse resp = httpclient.execute(httpPost);
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();
        	
	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}
	
	public static HttpResult deleteSSL(String urlString, SSLContext sslContext) {
		CloseableHttpClient httpclient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.setSSLContext(sslContext)
        		.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE)
				.build();
		
    	HttpResult result = new HttpResult();
	    try {

	    	CloseableHttpResponse resp = httpclient.execute(new HttpDelete(urlString));
        	result.setHttpStatus( resp.getStatusLine().getStatusCode() );
        	if (resp.getEntity() != null) {
        		result.setContent(EntityUtils.toString(resp.getEntity()));
        	}
        	resp.close();

	    } catch (Exception ex) {
	    	result.setReqStatus(-1);
	    	result.setReqError(ex.getMessage());
	    	
	    	ex.printStackTrace();
	    	try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
		
		return result;
	}
}
